package Bencode

import (
	"bufio"
	"errors"
	"io"
)

var ErrorType = errors.New("类型错误")

// BType 定义BType类型，表示Torrent File（种子文件）中出现字段的类型
type BType uint8

// BType类型的枚举常量
const (
	BSTR BType = iota
	BINT
	BLIST
	BDIST
)

// BValue 定义BValue类型,表示Torrent File（种子文件）中出现字段的值
type BValue interface{}

// BObject 类型+值，用来表示Torrent File（种子文件）的一个完整字段
type BObject struct {
	type_ BType
	val_  BValue
}

func (b *BObject) str() (string, error) {
	if b.type_ != BSTR {
		return "", ErrorType
	}
	return b.val_.(string), nil
}

func (b *BObject) int() (int, error) {
	if b.type_ != BINT {
		return 0, ErrorType
	}
	return b.val_.(int), nil
}

func (b *BObject) list() ([]*BObject, error) {
	if b.type_ != BLIST {
		return nil, ErrorType
	}
	return b.val_.([]*BObject), nil
}
func (b *BObject) Dict() (map[string]*BObject, error) {
	if b.type_ != BDIST {
		return nil, ErrorType
	}
	return b.val_.(map[string]*BObject), nil
}

// Bencode 将Go语言实例序列化为种子文件
func (b *BObject) Bencode(w io.Writer) (writedByteLen int, err error) {
	writedByteLen = 0
	writer := bufio.NewWriter(w)

	switch b.type_ {
	case BSTR:
		str, _ := b.str()
		byteLen, err := EncodeString(w, str)
		if err != nil {
			return
		}
		writedByteLen += byteLen
		return
	case BINT:
		n, _ := b.int()
		byteLen, err := EncodeInt(w, n)
		if err != nil {
			return
		}
		writedByteLen += byteLen
		return
	case BLIST:
		sliceBObject, _ := b.list()
		writer.WriteByte('l')
		byteLen := 0
		for _, value := range sliceBObject {
			byteLen, _ = value.Bencode(w)
			writedByteLen += byteLen
		}
		writer.WriteByte('e')
		writedByteLen += 2

	case BDIST:
		mapBObject, _ := b.Dict()
		writer.WriteByte('d')
		for key, value := range mapBObject {
			keyByte, _ := EncodeString(w, key)
			writedByteLen += keyByte
			valueByte, _ := value.Bencode(w)
			writedByteLen += valueByte
		}
		writer.WriteByte('e')
		writedByteLen += 2
	}

	writer.Flush()
	return writedByteLen, nil
}

// Bdecode 将种子文件反序列化为Go中的实例（即解析）
func (b *BObject) Bdecode(w io.Writer) (writedByteLen int, err error) {

}
